#include <stdio.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "driver/gpio.h"
#include <driver/rmt.h>


#include "m_led.h"
#include "m_ble.h"
#include "m_ethernet.h"
#include "m_http_client.h"
#include "m_uart.h"
#include "m_config.h"

led_status_e led_status = led_status_device_start;
xQueueHandle led_evt_queue = NULL;					//Creat led event queue
extern uint8_t isWifiConnectOk;

// RTM param
#define LED_RMT_TX_CHANNEL RMT_CHANNEL_0
#define RMT_CLK_DIV 2
#define T0H 14
#define T1H 28
#define T0L 40
#define T1L 32
#define TRES 14 * 1000 //reset time

// ws2812 Param
#define LED_NUM 8
#define BITS_PER_LED_CMD 24
#define LED_BUFFER_ITEMS ((LED_NUM * BITS_PER_LED_CMD))

rmt_item32_t led_data_buffer[LED_BUFFER_ITEMS];

// led Param
typedef union
{

	struct __attribute__((packed))
	{
		uint8_t r, g, b;
	};
	uint32_t rgb;
} rgb_color;

rgb_color set_LedRGB(uint8_t r, uint8_t g, uint8_t b)
{
	rgb_color v;

	v.r = b;
	v.g = r;
	v.b = g;
	return v;
}

static rgb_color pixels[LED_NUM];


static void RGBtoHSV( float r, float g, float b, float *h, float *s, float *v )
{
    float min, max, delta;
	max = (r > g) ? r : g;
	if (b > max) {
	    max = b;
	}

	min = (r < g) ? r : g;
	if (b < min) {
	    min = b;
	}

    *v = max;               // v
    delta = max - min;
    if( max != 0 )
        *s = delta / max;       // s
    else {
        // r = g = b = 0        // s = 0, v is undefined
        *s = 0;
        *h = -1;
        return;
    }
    if( r == max )
        *h = ( g - b ) / delta;     // between yellow & magenta
    else if( g == max )
        *h = 2 + ( b - r ) / delta; // between cyan & yellow
    else
        *h = 4 + ( r - g ) / delta; // between magenta & cyan
    *h *= 60;               // degrees
    if( *h < 0 )
        *h += 360;
}
 
static void HSVtoRGB( float *r, float *g, float *b, float h, float s, float v )
{
	// R,G,B from 0-255, H from 0-360, S,V from 0-100
	int i;
	float RGB_min, RGB_max;
	RGB_max = v*2.55f;
	RGB_min = RGB_max*(100 - s) / 100.0f;

	i = h / 60;
	int aa = h;
	int difs = aa % 60; // factorial part of h

	// RGB adjustment amount by hue 
	float RGB_Adj = (RGB_max - RGB_min)*difs / 60.0f;

	switch (i) {
	case 0:
		*r = RGB_max;
		*g = RGB_min + RGB_Adj;
		*b = RGB_min;
		break;
	case 1:
		*r = RGB_max - RGB_Adj;
		*g = RGB_max;
		*b = RGB_min;
		break;
	case 2:
		*r = RGB_min;
		*g = RGB_max;
		*b = RGB_min + RGB_Adj;
		break;
	case 3:
		*r = RGB_min;
		*g = RGB_max - RGB_Adj;
		*b = RGB_max;
		break;
	case 4:
		*r = RGB_min + RGB_Adj;
		*g = RGB_min;
		*b = RGB_max;
		break;
	default:		// case 5:
		*r = RGB_max;
		*g = RGB_min;
		*b = RGB_max - RGB_Adj;
		break;
	}
}



/**************************************************************
* 初始化LED WS2812 RTM
* @param[in]   gpio_num 	:led控制引脚编号
* @retval      void			:无
* @note
*/
void ws2812_control_init(gpio_num_t gpio_num)
{
	rmt_config_t config;
	config.rmt_mode = RMT_MODE_TX;
	config.channel = LED_RMT_TX_CHANNEL;
	config.gpio_num = gpio_num;
	config.mem_block_num = 1;
	config.tx_config.loop_en = false;
	config.tx_config.carrier_en = false;
	config.tx_config.idle_output_en = true;
	config.tx_config.idle_level = 0;
	config.clk_div = RMT_CLK_DIV;

	ESP_ERROR_CHECK(rmt_config(&config));
	ESP_ERROR_CHECK(rmt_driver_install(config.channel, 0, 0));
}

/**************************************************************
* 设置RTM数据buf
* @param[in]   led_color 	:led灯颜色参数
* @retval      void			:无
* @note
*/
void setup_rmt_data_buffer(rgb_color *led_color)
{
	for (uint32_t led = 0; led < LED_NUM; led++)
	{
		uint32_t bits_to_send = led_color[led].rgb;
		uint32_t mask = 1 << (BITS_PER_LED_CMD - 1);
		for (uint32_t bit = 0; bit < BITS_PER_LED_CMD; bit++)
		{
			uint32_t bit_is_set = bits_to_send & mask;
			led_data_buffer[led * BITS_PER_LED_CMD + bit] = bit_is_set ? (rmt_item32_t){{{T1H, 1, T1L, 0}}} : (rmt_item32_t){{{T0H, 1, T0L, 0}}};
			mask >>= 1;
		}
	}
}

/**************************************************************
* 利用RTM驱动ws2812，点亮LED
* @param[in]   led_color 	:led灯颜色参数
* @retval      void			:无
* @note
*/
void ws2812_write_leds(rgb_color *led_color)
{
	#ifdef usr_use_led_or_old
	setup_rmt_data_buffer(led_color);
	ESP_ERROR_CHECK(rmt_write_items(LED_RMT_TX_CHANNEL, led_data_buffer, LED_BUFFER_ITEMS, false));
	ESP_ERROR_CHECK(rmt_wait_tx_done(LED_RMT_TX_CHANNEL, portMAX_DELAY));
	#endif
}

/**************************************************************
* 初始化WS2812
* @param[in]   void			:无
* @retval      void			:无
* @note
*/
void init_ws2812(void)
{
	ws2812_control_init(RGB_LED);

	for (int i = 0; i < LED_NUM; i++)
	{
		pixels[i] = set_LedRGB(0, 0, 0);
	}

	ws2812_write_leds(pixels);
}

/**************************************************************
* LED控制函数
* @param[in]   arg			:无
* @retval      void			:无
* @note
*/
void led_control_data_pool(void)
{
	rgb_color pool[LED_NUM];

	float h,s,v,r,g,b;
	RGBtoHSV(100,100,0,&h,&s,&v);

	printf("HSV: %f,%f,%f\r\n",h,s,v);
	for (int i = 0; i < LED_NUM; i++)
	{
		//pool[i] = set_LedRGB(led_color_control[color+i][1], led_color_control[color+i][2], led_color_control[color+i][3]);
		v = v + 3*i;
		HSVtoRGB(&r,&g,&b,h,s,v);
		printf("RGB: %f,%f,%f\r\n",r,g,b);

		pool[i] = set_LedRGB(g, r, b);
	}
	
	int k = 0;
	for (int j = 0; j < 300; j++)
	{
		for (int n = 0; n < LED_NUM; n++)
		{
			k = j%LED_NUM;

			if(n+k < LED_NUM)
			{
				pixels[LED_NUM-1-n] = pool[n+k];
			}
			else
			{
				pixels[LED_NUM-1-n] = pool[n+k-LED_NUM];
			}
		}
		ws2812_write_leds(pixels);
		vTaskDelay(150 / portTICK_PERIOD_MS);
	}
}

void led_control_event_start(void)
{
	rgb_color pool[LED_NUM];

	for (int i = 0; i < LED_NUM; i++)
	{
		pool[i] = set_LedRGB(0, 0, 100);
	}
	pool[0] = set_LedRGB(40, 210, 200);

	int k = 0;
	for (int j = 0; j < 40; j++)
	{
		for (int n = 0; n < LED_NUM; n++)
		{
			k = j%LED_NUM;

			if(n+k < LED_NUM)
			{
				pixels[LED_NUM-1-n] = pool[n+k];
			}
			else
			{
				pixels[LED_NUM-1-n] = pool[n+k-LED_NUM];
			}
		}
		ws2812_write_leds(pixels);
		vTaskDelay(100 / portTICK_PERIOD_MS);
	}

	pool[0] = set_LedRGB(0, 0, 100);
	ws2812_write_leds(pool);

	led_status_e led_status = led_status_wifi_connecting;
	xQueueSend(led_evt_queue, &led_status, NULL);
}

void led_control_event_wifi_connecting(void)
{
	rgb_color pool[LED_NUM];

	for (int i = 0; i < LED_NUM; i++)
	{
		pool[i] = set_LedRGB(120, 120, 0);
	}
	pool[0] = set_LedRGB(255, 255, 70);
	pool[4] = set_LedRGB(255, 255, 70);
	pool[8] = set_LedRGB(255, 255, 70);

	int k = 0, j = 0;
	while(1)
	{
		j++;
		for (int n = 0; n < LED_NUM; n++)
		{
			k = j%LED_NUM;

			if(n+k < LED_NUM)
			{
				pixels[LED_NUM-1-n] = pool[n+k];
			}
			else
			{
				pixels[LED_NUM-1-n] = pool[n+k-LED_NUM];
			}
		}
		ws2812_write_leds(pixels);
		vTaskDelay(150 / portTICK_PERIOD_MS);

		if(isWifiConnectOk)
		{
			led_status = led_status_wifi_connected;
			xQueueSend(led_evt_queue, &led_status, NULL);
			break;
		}
	}
}

void led_control_event_wifi_timeout(void)
{
	rgb_color pool[LED_NUM];

	for(int m = 0; m < 6; m++)
	{
		for (int i = 0; i < LED_NUM; i++)
		{
			if(m%2 == 0)
			{
				pool[i] = set_LedRGB(0, 0, 0);
			}
			else
			{
				pool[i] = set_LedRGB(255, 0, 0);
			}
		}
		
		ws2812_write_leds(pool);
		vTaskDelay(400 / portTICK_PERIOD_MS);
	}
}

void led_control_event_wifi_connected(void)
{
	rgb_color pool[LED_NUM];

	for(int m = 0; m < 5; m++)
	{
		for (int i = 0; i < LED_NUM; i++)
		{
			if(m%2 == 0)
			{
				pool[i] = set_LedRGB(0, 0, 0);
			}
			else
			{
				pool[i] = set_LedRGB(120, 120, 0);
			}
		}
		
		ws2812_write_leds(pool);
		vTaskDelay(400 / portTICK_PERIOD_MS);
	}
}

void led_control_event_socket_connecting(void)
{
	rgb_color pool[LED_NUM];

	for (int i = 0; i < LED_NUM; i++)
	{
		pool[i] = set_LedRGB(120, 0, 120);
	}
	pool[0] = set_LedRGB(255, 70, 255);
	pool[4] = set_LedRGB(255, 70, 255);
	pool[8] = set_LedRGB(255, 70, 255);
	
	int k = 0, j = 0;
	while(1)
	{
		j++;
		for (int n = 0; n < LED_NUM; n++)
		{
			k = j%LED_NUM;

			if(n+k < LED_NUM)
			{
				pixels[LED_NUM-1-n] = pool[n+k];
			}
			else
			{
				pixels[LED_NUM-1-n] = pool[n+k-LED_NUM];
			}
		}
		ws2812_write_leds(pixels);
		vTaskDelay(150 / portTICK_PERIOD_MS);

		if(isWifiConnectOk)
		{
			break;
		}
	}
}


void led_control_event_socket_error(void)
{
	rgb_color pool[LED_NUM];

	for(int m = 0; m < 2; m++)
	{
		for (int i = 0; i < LED_NUM; i++)
		{
			if(m%2 == 0)
			{
				pool[i] = set_LedRGB(0, 0, 0);
			}
			else
			{
				pool[i] = set_LedRGB(255, 0, 0);
			}
		}
		
		ws2812_write_leds(pool);
		vTaskDelay(400 / portTICK_PERIOD_MS);
	}
}

void led_control_event_socket_connected(void)
{
	rgb_color pool[LED_NUM];

	for(int m = 0; m < 5; m++)
	{
		for (int i = 0; i < LED_NUM; i++)
		{
			if(m%2 == 0)
			{
				pool[i] = set_LedRGB(0, 0, 0);
			}
			else
			{
				pool[i] = set_LedRGB(120, 0, 120);
			}
		}
		
		ws2812_write_leds(pool);
		vTaskDelay(400 / portTICK_PERIOD_MS);
	}
}

void led_control_event_socket_senddata(void)
{
	rgb_color pool[LED_NUM];

	for(int m = 0; m < 4; m++)
	{
		for (int i = 0; i < LED_NUM; i++)
		{
			if(m%2 == 0)
			{
				pool[i] = set_LedRGB(255, 0, 0);
			}
			else
			{
				pool[i] = set_LedRGB(0, 0, 0);
			}
		}
		
		ws2812_write_leds(pool);
		vTaskDelay(400 / portTICK_PERIOD_MS);
	}
}

/**************************************************************
* LED控制task
* @param[in]   arg			:无
* @retval      void			:无
* @note
*/
static void led_process_task(void* arg)
{
    uint8_t led_control_data;
	
    for(;;) {
        if(xQueueReceive(led_evt_queue, &led_control_data, portMAX_DELAY)) 
		{   
		   switch (led_control_data)
		   {
		   case led_status_device_start:
				led_control_event_start();
			   break;
		   case led_status_wifi_connecting:
				led_control_event_wifi_connecting();
			   break;
		   case led_status_wifi_timeout:
				led_control_event_wifi_timeout();
			   break;
		   case led_status_wifi_connected:
				led_control_event_wifi_connected();
			   break;
		   case led_status_socket_conneting:
				led_control_event_socket_connecting();
			   break;
		   case led_status_socket_connected:
				led_control_event_socket_connected();
			   break;
		   case led_status_socket_error:
				led_control_event_socket_error();
			   break;
		   case led_status_device_alarm:
			   led_control_event_socket_senddata();
			   break;
			   
		   default:
		   	   
			   break;
		   }
		}
    }
}

/**************************************************************
* LED初始化
* @param[in]   viod			:无
* @retval      void			:无
* @note
*/
void  led_init(void)
{
	init_ws2812();

	led_evt_queue = xQueueCreate(10, sizeof(uint8_t));
	
	xTaskCreate(led_process_task, "led_process", 2048, NULL, 4, NULL);

	led_status_e led_status = led_status_device_start;
	xQueueSend(led_evt_queue, &led_status, NULL);
}


